Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Commit ff59f9d34e128b3eefb925fdc4d75670e30abbd6


Parents : 19fdafa
Author : Ivan <ivan@quad4.io>
Signature : Signature validation error
Date : 2026-04-23T04:31:00-05:00

feat(translatorHandler): update URL handling by normalizing loopback URLs and preventing unsafe outbound requests

Changes

1 files changed, 22 insertions(+), 2 deletions(-)


Diff

diff --git a/meshchatx/src/backend/translator_handler.py b/meshchatx/src/backend/translator_handler.py
index 4fb5e1b8..f73a100a 100644
--- a/meshchatx/src/backend/translator_handler.py
+++ b/meshchatx/src/backend/translator_handler.py
@@ -8,6 +8,8 @@ import shutil
import subprocess
from typing import Any
+from meshchatx.src.backend.http_url_guard import UnsafeOutboundUrlError, normalize_loopback_http_service_base
+
try:
import aiohttp
@@ -99,9 +101,13 @@ class TranslatorHandler:
self.has_requests = HAS_AIOHTTP
async def _fetch_languages_async(self, url: str):
+ base = url.rstrip("/")
timeout = aiohttp.ClientTimeout(total=5)
async with aiohttp.ClientSession(timeout=timeout) as session:
- async with session.get(f"{url}/languages") as response:
+ async with session.get(
+ f"{base}/languages",
+ allow_redirects=False,
+ ) as response:
if response.status == 200:
return await response.json()
return None
@@ -112,6 +118,12 @@ class TranslatorHandler:
return languages
url = libretranslate_url or self.libretranslate_url
+ if libretranslate_url is not None and str(libretranslate_url).strip():
+ try:
+ url = normalize_loopback_http_service_base(libretranslate_url)
+ except UnsafeOutboundUrlError as e:
+ msg = str(e)
+ raise ValueError(msg) from e
if self.has_requests:
try:
@@ -178,6 +190,12 @@ class TranslatorHandler:
if self.has_requests:
try:
url = libretranslate_url or self.libretranslate_url
+ if libretranslate_url is not None and str(libretranslate_url).strip():
+ try:
+ url = normalize_loopback_http_service_base(libretranslate_url)
+ except UnsafeOutboundUrlError as e:
+ msg = str(e)
+ raise ValueError(msg) from e
return self._translate_libretranslate(
text,
source_lang=source_lang,
@@ -202,16 +220,18 @@ class TranslatorHandler:
target_lang: str,
libretranslate_url: str,
) -> dict[str, Any]:
+ base = libretranslate_url.rstrip("/")
timeout = aiohttp.ClientTimeout(total=30)
async with aiohttp.ClientSession(timeout=timeout) as session:
async with session.post(
- f"{libretranslate_url}/translate",
+ f"{base}/translate",
json={
"q": text,
"source": source_lang,
"target": target_lang,
"format": "text",
},
+ allow_redirects=False,
) as response:
if response.status != 200:
body = await response.text()


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────